package com.kevin.permission.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.kevin.permission.dao.SysAclMapper;
import com.kevin.permission.dao.SysAclModuleMapper;
import com.kevin.permission.dao.SysDeptMapper;
import com.kevin.permission.dto.AclDto;
import com.kevin.permission.dto.AclModuleLevelDto;
import com.kevin.permission.dto.DeptLevelDto;
import com.kevin.permission.model.SysAcl;
import com.kevin.permission.model.SysAclModule;
import com.kevin.permission.model.SysDept;
import com.kevin.permission.util.JsonMapper;
import com.kevin.permission.util.LevelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.acl.Acl;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysTreeService {

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysAclModuleMapper sysAclModuleMapper;

    @Autowired
    private SysCoreService sysCoreService;

    @Autowired
    private SysAclMapper sysAclMapper;

    public List<AclModuleLevelDto> userAclTree(int userId) {
        List<SysAcl> userAclList=sysCoreService.getUserAclList(userId);
        List<AclDto> aclDtoList=Lists.newArrayList();
        for (SysAcl acl:userAclList){
            AclDto dto=AclDto.adapter(acl);
            dto.setHasAcl(true);
            dto.setChecked(true);
            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }

    //TODO 角色树形结构
    public List<AclModuleLevelDto> roleTree(int roleId) {
        //1.当前用户已分配权限点
        List<SysAcl> userAclList=sysCoreService.getCurrentUserAclList();
        //2.当前角色分配的权限点
        List<SysAcl> roleAclList=sysCoreService.getRoleAclList(roleId);
        //3.当前系统的所有权限点
        List<AclDto> aclDtoList=Lists.newArrayList();

        Set<Integer> userAclIdSet=userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        Set<Integer> roleAclIdSet=roleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        List<SysAcl> allAclList=sysAclMapper.getAll();
        for (SysAcl acl:allAclList){
            AclDto dto=AclDto.adapter(acl);
            if (userAclIdSet.contains(acl.getId())){
                dto.setHasAcl(true);
            }
            if (roleAclIdSet.contains(acl.getId())){
                dto.setChecked(true);
            }
            aclDtoList.add(dto);
        }
        return aclListToTree(aclDtoList);
    }

    private List<AclModuleLevelDto> aclListToTree(List<AclDto> aclDtoList) {
        if (CollectionUtils.isEmpty(aclDtoList)){
            return Lists.newArrayList();
        }

        List<AclModuleLevelDto> aclModuleLevelDtoList=aclModuleTree();
        log.info("权限模块树{}", JsonMapper.obj2String(aclModuleLevelDtoList));
        Multimap<Integer,AclDto> moduleIdAclMap=ArrayListMultimap.create();

        for (AclDto acl:aclDtoList){
            if (acl.getStatus()==1){
                moduleIdAclMap.put(acl.getAclModuleId(),acl);
            }
        }
        bindAclsWithOrder(aclModuleLevelDtoList,moduleIdAclMap);
        log.info("绑定后，角色权限列表树{}", JsonMapper.obj2String(aclModuleLevelDtoList));
        return aclModuleLevelDtoList;
    }

    private void bindAclsWithOrder(List<AclModuleLevelDto> aclModuleLevelList, Multimap<Integer, AclDto> moduleIdAclMap) {
        if (CollectionUtils.isEmpty(aclModuleLevelList)){
            return ;
        }
        for (AclModuleLevelDto dto:aclModuleLevelList){
            List<AclDto> aclDtoList= (List<AclDto>) moduleIdAclMap.get(dto.getId());
            if (CollectionUtils.isNotEmpty(aclDtoList)){
                Collections.sort(aclDtoList,aclSeqComparator);
                dto.setAclList(aclDtoList);
            }
            bindAclsWithOrder(dto.getAclModuleLevelDtoList(),moduleIdAclMap);
        }
    }


    public List<AclModuleLevelDto> aclModuleTree() {

        List<SysAclModule> aclModuleList=sysAclModuleMapper.getAllAclModule();
        List<AclModuleLevelDto> dtoList=Lists.newArrayList();
        for (SysAclModule aclModule: aclModuleList){
            dtoList.add(AclModuleLevelDto.adpter(aclModule));
        }

        return aclModuleListToTree(dtoList);
    }

    private List<AclModuleLevelDto> aclModuleListToTree(List<AclModuleLevelDto> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)){
            return Lists.newArrayList();
        }

        Multimap<String,AclModuleLevelDto> levelAclModuleMap=ArrayListMultimap.create();
        List<AclModuleLevelDto> rootList=Lists.newArrayList();

        for (AclModuleLevelDto dto:dtoList){
            levelAclModuleMap.put(dto.getLevel(),dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())){
                rootList.add(dto);
            }
        }
        Collections.sort(rootList,aclModuleSeqComparator);
        transforAclModuleTree(rootList,LevelUtil.ROOT,levelAclModuleMap);
        return rootList;
    }

    private void transforAclModuleTree(List<AclModuleLevelDto> dtoList, String level, Multimap<String, AclModuleLevelDto> levelAclModuleMap) {
        for (int i=0;i<dtoList.size();i++){
            AclModuleLevelDto dto=dtoList.get(i);
            String nextLevel=LevelUtil.calculateLevel(level,dto.getId());
            List<AclModuleLevelDto> tempList= (List<AclModuleLevelDto>) levelAclModuleMap.get(nextLevel);
            if(CollectionUtils.isNotEmpty(tempList)){
                Collections.sort(tempList,aclModuleSeqComparator);
                dto.setAclModuleLevelDtoList(tempList);
                transforAclModuleTree(tempList,nextLevel,levelAclModuleMap);
            }
        }
    }

    public List<DeptLevelDto> deptTree(){
        List<SysDept> deptList=sysDeptMapper.getAllDept();

        List<DeptLevelDto> dtoList= Lists.newArrayList();

        for (SysDept dept:deptList){
            DeptLevelDto dto=DeptLevelDto.adapter(dept);
            dtoList.add(dto);
        }

        return deptListToTree(dtoList);
    }

    private List<DeptLevelDto> deptListToTree(List<DeptLevelDto> deptLevelList) {
        if (CollectionUtils.isEmpty(deptLevelList)){
            return Lists.newArrayList();
        }
        // level -> [dept1, dept2, ...] Map<String, List<Object>>
        Multimap<String ,DeptLevelDto> levelDeptMap= ArrayListMultimap.create();
        List<DeptLevelDto> rootList=Lists.newArrayList();

        for (DeptLevelDto dto:deptLevelList){
            levelDeptMap.put(dto.getLevel(),dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())){
                rootList.add(dto);
            }
        }
        // 按照seq从小到大排序
        Collections.sort(rootList, new Comparator<DeptLevelDto>() {
            public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                return o1.getSeq()-o2.getSeq();
            }
        });
        //递归生成树
        transformDeptTree(rootList,LevelUtil.ROOT,levelDeptMap);
        return rootList;
    }

    private void transformDeptTree(List<DeptLevelDto> deptLevelList, String level, Multimap<String, DeptLevelDto> levelDeptMap) {
        for (int i=0;i<deptLevelList.size();i++){
            //遍历该层的每个元素
            DeptLevelDto deptLevelDto=deptLevelList.get(i);
            //处理当层的数据
            String nextLevel=LevelUtil.calculateLevel(level,deptLevelDto.getId());
            //处理下一层
            List<DeptLevelDto> tempDeptList=(List<DeptLevelDto>)levelDeptMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempDeptList)){
                //排序
                Collections.sort(tempDeptList,deptLevelDtoComparator);
                //设置下一层部门
                deptLevelDto.setDeptList(tempDeptList);
                //进入到下一层处理
                transformDeptTree(tempDeptList,nextLevel,levelDeptMap);
            }
        }
    }

    public Comparator<DeptLevelDto> deptLevelDtoComparator=new Comparator<DeptLevelDto>() {
        public int compare(DeptLevelDto o1, DeptLevelDto o2) {
            return o1.getSeq()-o2.getSeq();
        }
    };

    public Comparator<AclModuleLevelDto> aclModuleSeqComparator=new Comparator<AclModuleLevelDto>() {
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq()-o2.getSeq();
        }
    };

    public Comparator<AclDto> aclSeqComparator = new Comparator<AclDto>() {
        public int compare(AclDto o1, AclDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };


}
